package cc.iotkit.manager.service;

import cc.iotkit.common.api.Paging;
import cc.iotkit.common.api.Response;
import cc.iotkit.common.utils.MapstructUtils;
import cc.iotkit.data.IOwnedData;
import cc.iotkit.data.dao.IJPACommData;
import cc.iotkit.data.dao.WzrGroupDeviceInfoRepository;
import cc.iotkit.data.dao.WzrGwDevGroupRepository;
import cc.iotkit.data.dao.WzrGwDevRepository;
import cc.iotkit.data.model.*;
import cc.iotkit.data.service.DeviceInfoDataImpl;
import cc.iotkit.manager.dto.bo.devicegroup.WzrGroupBo;
import cc.iotkit.model.device.DeviceGroup;
import cc.iotkit.model.device.DeviceInfo;
import cn.hutool.core.util.IdUtil;

import io.vertx.core.json.JsonArray;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import org.springframework.stereotype.Service;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.lang.reflect.Array;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;

import static cc.iotkit.data.model.QTbDeviceInfo.tbDeviceInfo;

/**
 * 微自然网关和设备的主要逻辑类
 * 包含网关业务和子设备业务
 * 网关业务主要包含：组网，定时任务，群组任务
 * 设备业务主要包含：属性
 */
@Slf4j
@Service
public class WzrGwDevService {
    @Autowired
    private WzrGwDevRepository wzrGwDevRepository;
    @Autowired
    private IDeviceManagerService deviceServiceImpl;
    @Autowired
    private DeviceCtrlService deviceCtrlService;
    @Autowired
    private WzrGwDevGroupRepository wzrGwDevGroupRepository;
    @Autowired
    private WzrGroupDeviceInfoRepository groupDeviceInfoRepository;
    @Autowired
    private EntityManager entityManager;



    /**
     * 微自然网关组网，设备与网关关联
     * @param gwid
     * @param devid
     * @return
     */
    public Response setDevToGw(String gwid,String devid,String rsid,String service){

        //查询设备和网关
        DeviceInfo deviceInfo = deviceServiceImpl.getDetail(devid);
        if (deviceInfo == null) {
            return new Response<>(500,"设备id不正确",deviceInfo,rsid);
        }
        DeviceInfo gwDeviceInfo = deviceServiceImpl.getDetail(gwid);
        if (gwDeviceInfo == null) {
            return new Response<>(500,"网关id不正确",gwDeviceInfo,rsid);
        }
        //查询当前网关的最近递增编号
        TbWzrGwDev wzrGwDev1 = wzrGwDevRepository.findBygwName(gwDeviceInfo.getDeviceName());
        //如果平台有这个设备，但是微自然设备网关库里没这个设备，说明这个设备是首次出现，pvid=1
        HashMap map = new HashMap();
        int pvid = 1;
        if (wzrGwDev1 != null) {
            pvid = wzrGwDev1.getGwPvid()+1;
        }
        if (service.equals("pvid")) {
            //查询设备是否已经绑定
            TbWzrGwDev wzrGwDev = wzrGwDevRepository.findBydeviceId(devid);
            if (wzrGwDev != null) {
                return new Response<>(500,"当前设备已经被添加到其他网关",wzrGwDev,rsid);
            }
            map.put("gwmac", pvid);
            map.put("devmac",deviceInfo.getDeviceName());
        }
        if (service.equals("dvid")) {
            JsonArray jsonArray = new JsonArray();
            map.put("gwmac", pvid);
            map.put("devmac",jsonArray);
        }
        map.put("gwinfo",gwDeviceInfo.getDeviceName());
        //向组件发送消息
        TbWzrGwDev tbWzrGwDev = new TbWzrGwDev();
        tbWzrGwDev.setDeviceId(devid);
        tbWzrGwDev.setId(UUID.randomUUID().toString());
        tbWzrGwDev.setDeviceName(deviceInfo.getDeviceName());
        tbWzrGwDev.setDeviceMac(deviceInfo.getDeviceName());
        tbWzrGwDev.setProductKey(deviceInfo.getProductKey());
        tbWzrGwDev.setGwPvid(pvid);
        tbWzrGwDev.setGwName(gwDeviceInfo.getDeviceName());
        tbWzrGwDev.setId(UUID.randomUUID().toString());
        wzrGwDevRepository.save(tbWzrGwDev);
        return new Response(200,"发送消息至网关",deviceCtrlService.invokeService(gwid,service,map),rsid);
    }
    /**
     * 群组设备的增改删业务
     * 业务逻辑，先执行群组增改，再执行群组任务。
     * 如果没有设备增改，只有任务，则直接执行任务。
     * @param dto
     * @return
     */
    public Response addGroupDev(WzrGroupBo dto ){
        //确认网关存在
        DeviceInfo gwinfo = deviceServiceImpl.getDetail(dto.getGwId());
        if (gwinfo == null) {
            return new Response(500,"网关不存在",dto,IdUtil.simpleUUID());
        }
        TbWzrGwDevGroup group = wzrGwDevGroupRepository.getReferenceById(dto.getGroupid());
        if (group .getId() == 0) {
            return new Response(200,"当前群组不存在",dto,IdUtil.simpleUUID());
        }
        //开灯
        if (dto.isWorkstate()&&dto.getPercentage()>=0){
            group.setPercentage(dto.getPercentage());
            group.setWorkState(dto.isWorkstate());
            HashMap map = new HashMap();
            //调用网关服务
            map.put("percentage",dto.getPercentage());
           if (dto.getPercentage() != 0){
               map.put("workstate",1);
               group.setWorkState(true);
           }else {
               map.put("workstate",0);
               group.setWorkState(false);
           }
            deviceCtrlService.invokeService(gwinfo.getDeviceId(),"gatewayrpc",map);
            return new Response(200,"操作完成",wzrGwDevGroupRepository.saveAndFlush(group),IdUtil.simpleUUID());
        }
        //关灯
        if (!dto.isWorkstate()&&dto.getPercentage()==0){
            group.setPercentage(dto.getPercentage());
            group.setWorkState(dto.isWorkstate());
            HashMap map = new HashMap();
            //调用网关服务
            map.put("percentage",dto.getPercentage());
            if (dto.getPercentage() != 0){
                map.put("workstate",1);
                group.setWorkState(true);
            }else {
                map.put("workstate",0);
                group.setWorkState(false);
            }
            deviceCtrlService.invokeService(gwinfo.getDeviceId(),"gatewayrpc",map);
            return new Response(200,"操作完成",wzrGwDevGroupRepository.saveAndFlush(group),IdUtil.simpleUUID());
        }

        if (dto.getType()!=null&&dto.getType().equals("ae")){
            //增改业务,即子设备信息不为空
            for (String ids : dto.getDevids()){
                //如果是新增设备
                if (!ids.trim().isEmpty()){
                    //确认设备存在
//                    DeviceInfo devinfo = deviceServiceImpl.getDetail(ids);
//                    if (devinfo == null) {
//                        return new Response(500,"设备不存在",dto,IdUtil.simpleUUID());
//                    }
                    TbWzrGroupDeviceInfo wzrGroupDeviceInfo = new TbWzrGroupDeviceInfo();
                    wzrGroupDeviceInfo.setGroupId(String.valueOf(dto.getGroupid()));
                    wzrGroupDeviceInfo.setGwId(dto.getGwId());
                    wzrGroupDeviceInfo.setGwSkName(gwinfo.getDeviceName());
                    wzrGroupDeviceInfo.setDevid(ids);
//                    wzrGroupDeviceInfo.setDevName(devinfo.getDeviceName());
                    //获取设备组网的pid
                    TbWzrGwDev wzrGwDev = wzrGwDevRepository.findBydeviceId(ids);
//                    if (wzrGwDev == null) {
//                        return new Response(500,"设备没入网",dto,IdUtil.simpleUUID());
//                    }
                    //获得pvid和pmac
//                    int pvid = wzrGwDev.getGwPvid();
                    //测试期间pvid=1
                    int pvid = 1;
                    BigInteger pgidsum = group.getPgidsum();
                    if (pgidsum == null) {
                        pgidsum = BigInteger.ZERO;
                    }
                    //重新计算pgidsum
                    String pgmac = getPgidsum(pgidsum,pvid,true);
                    group.setPgidsum(new BigInteger(pgmac));
                    HashMap map = new HashMap();
                    //网关虚拟地址
                    map.put("pgmac", group.getPmac());
                    //子设备集合
                    map.put("dmc",pgmac);
                    //向组件推送服务消息并且下发到网关
                    deviceCtrlService.invokeService(gwinfo.getDeviceId(),"pgmac",map);
                    wzrGwDevGroupRepository.save(group);
                    wzrGroupDeviceInfo.setId(UUID.randomUUID().getMostSignificantBits());
                    groupDeviceInfoRepository.save(wzrGroupDeviceInfo);
                }
            }
            return new Response(200,"操作完成",null,IdUtil.simpleUUID());
        }
        //删除设备
        if (dto.getType()!=null&&dto.getType().equals("de")){
            for (String ids : dto.getDevids()){
                if (!ids.trim().isEmpty()) {
                    //确认设备存在
//                    DeviceInfo devinfo = deviceServiceImpl.getDetail(ids);
//                    if (devinfo == null) {
//                        return new Response(500, "设备不存在", dto, IdUtil.simpleUUID());
//                    }
                    //组装网络发送
//                    TbWzrGwDev wzrGwDev = wzrGwDevRepository.findBydeviceId(ids);
//                    if (wzrGwDev == null) {
//                        return new Response(500, "设备在当前网关下未组网", dto, IdUtil.simpleUUID());
//                    }
//                    int pvid = wzrGwDev.getGwPvid();
                    //测试时候，pvid=1
                    int pvid = 1;
                    BigInteger pgidsum = group.getPgidsum();
//                    String pgmac = getPgidsum(pgidsum,pvid,false);
                    //开发测试使用3
                    String pgmac = "3";
                    group.setPgidsum(new BigInteger(pgmac));
                    HashMap<String,Object> map = new HashMap<>();
                    //网关虚拟地址
                    map.put("pgmac", pvid);
                    //子设备集合
                    map.put("dmc",pgmac);
                    //查询这个设备所在网关，并且删除该条记录
//                    deviceCtrlService.invokeService(gwinfo.getDeviceName(),"pgmac",map);
                    wzrGwDevGroupRepository.save(group);
                    wzrGwDevRepository.deleteTbWzrGwDevByDeviceId(ids);
                    return new Response(200,"操作完成",null,IdUtil.simpleUUID());
                }
            }
        }
        return new Response(500,"操作类型必须提交",dto,IdUtil.simpleUUID());
    }

    //根据pgidsum计算所有设备的pid
    public ArrayList<Integer> getPvidByPgidsum(BigInteger pgidsum){
        ArrayList<Integer> arrayList = new ArrayList<>();
        String str = pgidsum.toString(2);
        int length = str.length();
        // 从右往左遍历字符串
        for (int i = length - 1; i >= 0; i--) {
            // 如果当前字符是'1'
            if (str.charAt(i) == '1') {
                // 计算从右往左的索引（这里直接输出，但你也可以存储起来）
                int fromIndexRight = length - 1 - i;
                arrayList.add(fromIndexRight+1);
            }
        }
        return arrayList;
    }
    //根据设备的pgidsum和pid计算新的pgidsum
    public String getPgidsum(BigInteger pgidsum,int pvid,boolean isadd){
        ArrayList<Integer> pgids = getPvidByPgidsum(pgidsum);
        if (isadd){
            //如果已经被增加，直接返回结果，否则增加
            if (pgids.contains(pvid)) {
                return pgidsum.toString();
            }
            pgids.add(pvid);
        }else {
            //如果有就移除，没有则不用处理
            if (pgids.contains(pvid)) {
                pgids.remove(pvid);
            }
        }
        BigInteger shiftedValue = BigInteger.ZERO;
        for (int i = 0; i < pgids.size(); i++) {
            BigInteger initialValue = BigInteger.ONE;
            shiftedValue = shiftedValue.add(initialValue.shiftLeft(pgids.get(i)-1));
        }
        return shiftedValue.toString(16);
    }

    /**
     * 分页查询已经入网的设备
     * @param page
     * @param size
     * @return
     */
    public Page<TbWzrGwDev> getPagingInGw(int page, int size) {
        return wzrGwDevRepository.findAllByPag(Pageable.ofSize(size).withPage(page));
    }

    public Paging<TbWzrGwDevGroup> findAllByPagNative(int page,int size) {
        String sql = "SELECT * FROM wzr_gw_dev_group";
        int offset = page;
        int pageSize = size;
        Query query = entityManager.createNativeQuery(sql, TbWzrGwDevGroup.class);
        query.setFirstResult(offset);
        query.setMaxResults(pageSize);
        List<TbWzrGwDevGroup> results = query.getResultList();
        return new Paging<>(offset, results);
    }
}